#include<stdio.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>

char linecommand[1024];
char* linestrtok[128];
int my_status = 0;
int my_signal = 0;

char filename[128];
int  redirect;
#define NORMAL 0 
#define WRITE 1
#define APPEND 2 
#define READ_IN 3 
char* pipe_s;

#define NOTEXISTPIPE NULL
int CommandCheckReindirizzare(int i ){
	
 		if(!strcmp(linestrtok[i - 2],">")){   //child or parent in current directory!!
			strcpy(filename,linestrtok[i-1]);
			linestrtok[i-1] = linestrtok[i - 2] = NULL;
			return WRITE;
		}
		else if(!strcmp(linestrtok[i-2],">>")){
			strcpy(filename,linestrtok[i-1]);
			linestrtok[i-1] = linestrtok[i - 2] = NULL;
			return APPEND;
		}
			
		else if(!strcmp(linestrtok[i-2],"<")){
			strcpy(filename,linestrtok[i-1]);
			linestrtok[i-1] = linestrtok[i-2] = NULL;		
			return READ_IN;
		} 
		else{
			return NORMAL;	
		}
} 
char* commandCheckPipe(int n){     //check pipe
	char* str = NULL;
	if(str = strchr(linecommand,'|')){
		*str = ' ';
		return str;
	}
	
	return NOTEXISTPIPE;
}
int main(){
	while(1){
		memset(linecommand,0,sizeof(linecommand));
		memset(linestrtok,0,sizeof(linestrtok));
		memset(filename,0,sizeof(filename));
		redirect = NORMAL;
		pipe_s = NOTEXISTPIPE;
		char* pwd = getenv("PWD");
		strtok(pwd,"/");
		char* last_pwd = NULL; 
		while(pwd= strtok(NULL,"/")){
			last_pwd = pwd;
		}
		char prompt = '$';
		if(!strcmp(getenv("USER"),"root")){
			prompt = '#';
		}
		printf("[%s@%s %s]%c ",getenv("USER"),getenv("HOSTNAME"),last_pwd,prompt);
		fgets(linecommand,sizeof(linecommand) - 1,stdin);
		linecommand[strlen(linecommand)-1] = '\0';
		int i = 0;
		pipe_s = commandCheckPipe(i);
		linestrtok[0] = strtok(linecommand," ");
		if(!strcmp(linestrtok[0],"exit")){
			printf("my shell success exit!!\n");
			break;
		}
		if(!strcmp(linestrtok[0],"ls")){     // ls is colour
			linestrtok[++i] = "--color=auto";
		}
		
		while(linestrtok[++i]=strtok(NULL," ")){
		}
		redirect = CommandCheckReindirizzare(i);
		
		if(!strcmp(linestrtok[0],"cd")){
			chdir(linestrtok[1]);
			continue;
		}
	
		if(!strcmp(linestrtok[0],"echo")){
			if(!strcmp(linestrtok[1],"$?")){
				printf("%d\n",my_status);
			}
			else{
				printf("%s\n",getenv(linestrtok[1]+1));
			}
			continue;
		}
	pid_t id = fork();
	if(!id){
		if(filename[0]){
			if(redirect == WRITE){
				int fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666);
				if(fd< 0){
					printf("fd open error!!\n");	
				}
				dup2(fd,1);
				close(fd);
			}
			if(redirect == APPEND){	
				int fd = open(filename,O_WRONLY | O_CREAT | O_APPEND,0666);
				if(fd< 0){
					printf("fd open error!!\n");	
				}
				dup2(fd,1);
				close(fd);
			}
			if(redirect == READ_IN){
				int fd = open(filename,O_RDONLY,0666);
				if(fd < 0){
					printf("fd open error!!\n");
				}
				dup2(fd,1);
				close(fd);
			}
		}
		if(!(*filename) && redirect){
			printf("redirect error please input redirect filename!!!\n");
			continue;
		}
		int pipefd[2] = {0};
		if(pipe_s){
			int n = 0;
			char* f_command[128] = { 0 } ;
			while(linestrtok[n] < pipe_s){
				f_command[n] = linestrtok[n];
				n++;
			}
			
			pipe(pipefd);

			pid_t id = fork();
			assert(id>=0);
			if(!id){
				dup2(pipefd[0],0);
				close(pipefd[0]);
				close(pipefd[1]);
				execvp(*(linestrtok + n),linestrtok + n);
				printf("pipe execvp error!!\n");
				exit(-1);
			}
			dup2(pipefd[1],1);
			close(pipefd[0]);
			close(pipefd[1]);
			execvp(*linestrtok,f_command);
			printf("execvp error!!\n");
			exit(-1);
		}
		else{
		execvp(*linestrtok,linestrtok);
		printf("execvp error!!\n");
		exit(-1);
		}
	}
	if(id<0){
		printf("my_bash create child error!!\n");
		exit(-1);
	}
	int status = 0;
	pid_t ret = waitpid(id,&status,0);
	if(ret>=0){
		if(WIFEXITED(status)){
			printf("child work success exit_code:%d\n",my_status=WEXITSTATUS(status));
		}
		else
			printf("child work error!! signal:%d\n",my_signal = WTERMSIG(status));
	}
	else{
		printf("my_bash wait child error!!\n");
		exit(-1);
	}
	}
	return 0;
}

